package com.ruoyi.huoxingshi.utils;

import com.qcloud.cos.COSClient;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.exception.CosClientException;
import com.qcloud.cos.http.HttpProtocol;
import com.qcloud.cos.model.ObjectMetadata;
import com.qcloud.cos.model.PutObjectRequest;
import com.qcloud.cos.model.PutObjectResult;
import com.qcloud.cos.model.UploadResult;
import com.qcloud.cos.region.Region;
import com.qcloud.cos.transfer.TransferManager;
import com.qcloud.cos.transfer.TransferManagerConfiguration;
import com.qcloud.cos.transfer.Upload;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.uuid.UUID;
import com.ruoyi.system.mapper.SysConfigMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Component
public class QCloudCosUtil {


    @Autowired
    private SysConfigMapper configMapper;


    private COSClient initClient() {
        String secretId = configMapper.checkConfigKeyUnique("qcloud.secret.id").getConfigValue();
        String secretKey = configMapper.checkConfigKeyUnique("qcloud.secret.key").getConfigValue();
        String regionName = configMapper.checkConfigKeyUnique("qcloud.region.name").getConfigValue();
        COSCredentials cred = new BasicCOSCredentials(secretId, secretKey);
        Region region = new Region(regionName);
        ClientConfig clientConfig = new ClientConfig(region);
        clientConfig.setHttpProtocol(HttpProtocol.https);
        clientConfig.setConnectionRequestTimeout(1000 * 60 * 10);
        clientConfig.setRequestTimeOutEnable(false);
        return new COSClient(cred, clientConfig);
    }

    // 创建 TransferManager 实例，这个实例用来后续调用高级接口
    private TransferManager createTransferManager() {
        // 创建一个 COSClient 实例，这是访问 COS 服务的基础实例。
        // 详细代码参见本页: 简单操作 -> 创建 COSClient
        COSClient cosClient = initClient();
        // 自定义线程池大小，建议在客户端与 COS 网络充足（例如使用腾讯云的 CVM，同地域上传 COS）的情况下，设置成16或32即可，可较充分的利用网络资源
        // 对于使用公网传输且网络带宽质量不高的情况，建议减小该值，避免因网速过慢，造成请求超时。
        ExecutorService threadPool = Executors.newFixedThreadPool(32);
        // 传入一个 threadpool, 若不传入线程池，默认 TransferManager 中会生成一个单线程的线程池。
        TransferManager transferManager = new TransferManager(cosClient, threadPool);
        return transferManager;
    }

    private void shutdownTransferManager(TransferManager transferManager) {
        // 指定参数为 true, 则同时会关闭 transferManager 内部的 COSClient 实例。
        // 指定参数为 false, 则不会关闭 transferManager 内部的 COSClient 实例。
        transferManager.shutdownNow(true);
    }

    public UploadInfo uploadFile(File file) {
        return uploadFile("/", file);
    }

    public UploadInfo uploadFile(String dir, File file) {
        String bucketName = configMapper.checkConfigKeyUnique("qcloud.bucket.name").getConfigValue();
        String baseUrl = configMapper.checkConfigKeyUnique("qcloud.web.url").getConfigValue();
        COSClient client = initClient();
        String fileName = file.getName();
        String suffixType = fileName.substring(fileName.lastIndexOf("."));
        String uploadName = UUID.randomUUID() + suffixType;
        try {
            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, dir + uploadName, file);
            // 设置存储类型（如有需要，不需要请忽略此行代码）, 默认是标准(Standard), 低频(standard_ia)
            // 更多存储类型请参见 https://cloud.tencent.com/document/product/436/33417
//            putObjectRequest.setStorageClass(StorageClass.Standard);
            PutObjectResult result = client.putObject(putObjectRequest);
            System.out.println(result.getRequestId());
            UploadInfo res = new UploadInfo();
            res.setUrl(baseUrl + dir + uploadName);
            res.setFileName(file.getName());
            res.setOriginalFilename(file.getName());
            res.setNewFileName(uploadName);
            res.setRequestId(result.getRequestId());
            return res;
        } catch (CosClientException e) {
            throw new ServiceException(e.getMessage());
        } finally {
            client.shutdown();
        }
    }

    public UploadInfo uploadFile(MultipartFile file) {
        return uploadFile("/", file);
    }

    public UploadInfo uploadFile(String dir, MultipartFile file) {
        String bucketName = configMapper.checkConfigKeyUnique("qcloud.bucket.name").getConfigValue();
        String baseUrl = configMapper.checkConfigKeyUnique("qcloud.web.url").getConfigValue();


        // 使用高级接口必须先保证本进程存在一个 TransferManager 实例，如果没有则创建
        // 详细代码参见本页：高级接口 -> 创建 TransferManager
        TransferManager transferManager = createTransferManager();
        // 设置高级接口的配置项
        // 分块上传阈值和分块大小分别设置为 5MB 和 1MB（若不特殊设置，分块上传阈值和分块大小的默认值均为5MB）
        TransferManagerConfiguration transferManagerConfiguration = new TransferManagerConfiguration();
        transferManagerConfiguration.setMultipartUploadThreshold(10 * 1024 * 1024);
        transferManagerConfiguration.setMinimumUploadPartSize(5 * 1024 * 1024);
        transferManager.setConfiguration(transferManagerConfiguration);

        String fileName = file.getOriginalFilename();
        String suffixType = null;
        if (fileName != null) {
            suffixType = fileName.substring(fileName.lastIndexOf("."));
        }
        String uploadName = UUID.randomUUID() + suffixType;


        try {
            ObjectMetadata objectMetadata = new ObjectMetadata();
            objectMetadata.setContentLength(file.getSize());
            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, dir + uploadName, file.getInputStream(), objectMetadata);

            Upload upload = transferManager.upload(putObjectRequest);
            UploadResult result = upload.waitForUploadResult();

            UploadInfo res = new UploadInfo();
            res.setUrl(baseUrl + dir + uploadName);
            res.setFileName(file.getOriginalFilename());
            res.setOriginalFilename(file.getOriginalFilename());
            res.setNewFileName(uploadName);
            res.setRequestId(result.getRequestId());

            return res;
        } catch (Exception e) {
            throw new ServiceException(e.getMessage());
        } finally {
            shutdownTransferManager(transferManager);
        }
    }


    public static class UploadInfo {
        private String requestId;
        private String fileName;
        private String newFileName;
        private String originalFilename;
        private String url;

        public String getUrl() {
            return url;
        }

        public void setUrl(String url) {
            this.url = url;
        }

        public String getRequestId() {
            return requestId;
        }

        public void setRequestId(String requestId) {
            this.requestId = requestId;
        }

        public String getFileName() {
            return fileName;
        }

        public void setFileName(String fileName) {
            this.fileName = fileName;
        }

        public String getNewFileName() {
            return newFileName;
        }

        public void setNewFileName(String newFileName) {
            this.newFileName = newFileName;
        }

        public String getOriginalFilename() {
            return originalFilename;
        }

        public void setOriginalFilename(String originalFilename) {
            this.originalFilename = originalFilename;
        }
    }

}